//全局变量、头文件区域
#include<stdio.h>
#include<string.h>
#define MAX 1024

//程序1
//利用指针模拟实现strcat拷贝
void test1()
{
	char str1[2*MAX];//防止越界
	char* targets1 = str1;
	printf("请输入第一个字符串：");
	fgets(str1, MAX, stdin);

	char str2[MAX];
	char* targets2 = str2;
	printf("请输入第二个字符串：");
	fgets(str2, MAX, stdin);

	//通过循环使得指针移动到最后'\0'处
	while (*targets1++ != '\0');

	
	targets1 -= 2;
	/*
		 此处的目的是为了将从fgets读取存入str1数组数据，利用指针进行修改。
		因为fgets并不会将'\n'与'\0', 过滤掉，所以需要将targets1指针指向的最后两个符号去除

		targets1 -= 2的目的是指针指向的位置调整
		*targets1 -= 2是进行指针指向的值进行-2操作
		例如：

		char str[] = "HACKED";//字符数组自动在末尾出添加'\0';实际数组str[] = {'H','A','C','K','E','D','\0'}
		char *targets1 = str;
		while(*targets1++ !=  '\0');//将指针移动到末尾,
		targets1 -= 1;//相当于将指针从str[6]移动到str[5] = 'D';
		*targets1 -= 1;//相当于去取出str[6]的值做减法

		
		例外数组中先存储'\0'才到'\n'，也就是最后一个符号是'\n'（因为我们是用户输入进去嘛，所以会键入'\n'）
		如果一开始初始化数组就将字符串常量给赋值进数组中，则不需要检测'\n'，按照例子进行处理，当然还有另一种方式消除fgets读取'\n'，例子是程序3
	*/

	while ((*targets1++ = *targets2++) != '\0');
	//此处代码是从targets1结尾开始，逐步将targets2值拼接上targets1末尾空白部分

	printf("连接后的结果是：%s", str1);

}

//程序2
//利用scanf搭配strcat函数实现拷贝
void test2()
{
	char str1[MAX];
	printf("请输入第一段字符串：");
	scanf("%s", str1);
	
	/*
		这里不用的fgets(str1, MAX, stdin)的原因是,fgets会读取到'\n'，若使用fgets的话程序3则会讲述如何过滤'\n'
		但是要用scanf的风险是：
		scanf()函数遇到空白符号就停止读取，这意味着如果输入的字符串中包括空格，scanf()只会读取到空格前的部分
		例如：

		char str[1024];
		scanf("%s",str);//这里用户输入"Hello World"
		printf("%s",str);//这里的结果为"Hello"

	*/
	char str2[MAX];
	printf("请输入第二段字符串：");
	scanf("%s", str2);

	
	strcat(str1, str2);
	/*
	strcat函数

	函数概要：

		strcat 函数用于连接两个字符串。
		将源字符串拷贝并连接到目标数组存放的字符串后边，此过程将覆盖第一个参数的结束符 '\0'。
		两个参数的位置不应该重叠。
	
	函数原型：

		#include <string.h>
		...
		char *strcat(char *dest, const char *src);
	
	参数解析：
	参数							含义
	dest						指向用于存放字符串的目标数组，它应该包含一个字符串，并且提供足够容纳连接后的总字符串长度的空间（包含结束符 '\0'）
	src							指向待连接的源字符串，该参数不应该与 dest 参数指向的位置发生重叠


	*/

	printf("连接结果：%s", str1);

}
//程序3
//实现用fgets搭配strcat函数使用实现拷贝
void test3()
{
	char str1[MAX];
	printf("请输入第一段字符串：");
	fgets(str1, MAX, stdin);
	//利用for循环过滤'\n'
	for (int i = 0; i < MAX; i++)//利用for循环遍历整个数组
	{
		//因为fgets在读取到字符串数组末尾'\n'，那我们只需要检测'\n'就能知道数组读取已经到最后一个字符了
		if (str1[i] == '\n')//将'\n'替换成'\0',过滤掉换行
		{
			str1[i] = '\0';
			break;
		}
	}

	char str2[MAX];
	printf("请输入第二段字符串：");
	fgets(str2, MAX, stdin);
	for (int i = 0; i < MAX; i++)
	{
		if (str2[i] == '\n')
		{
			str2[i] = '\0';
			break;
		}
	}

	strcat(str1, str2);
	printf("结果为：%s", str1);


}

//程序4
//利用指针模拟strcat函数实现拷贝（含中英文）
void test4()
{
	char str1[MAX];
	char* targets1 = str1;
	printf("请输入第一段字符串:");
	fgets(str1, MAX, stdin);
	for (int i = 0; i < MAX; i++)
	{
		if (str1[i] == '\n')
		{
			str1[i] = '\0';
			break;
		}
	}

	char str2[MAX];
	char* targets2 = str2;
	printf("请输入第二段字符串:");
	fgets(str2, MAX, stdin);
	for (int i = 0; i < MAX; i++)
	{
		if (str2[i] == '\n')
		{
			str2[i] = '\0';
			break;
		}
	}

	printf("请输入要连接的字符数：");
	int n;
	scanf("%d", &n);

	while (*targets1++ != '\0');

	targets1 -= 1;//这里和程序3有区别就是，我们在使用for循环去除'\n'，就不需要去除'\n'原先位置了，就只用消去'\0'


	char ch;
	while (n--)
	{
		
		ch = *targets1++ = *targets2++;
		if (ch == '\0')
		{
			break;
		}
		if ((int)ch < 0)
		{
			*targets1++ = *targets2++;
		}
	}
	*targets1++ = '\0';
	printf("连接的结果为:%s", str1);

}


//程序5
//利用strcat函数对选定字符进行拷贝
void test5()
{
	char str1[MAX];
	printf("请输入第一段字符串：");
	fgets(str1, MAX, stdin);

	//另一种方式，就是检测字符数组的有效长度，来确定循环次数,当然也直接循环整个数组长度，但是为了使程序能够快速响应，推荐使用这个方式处理循环次数
	int length = sizeof(str1) / sizeof(char);
	
	for (int i = 0; i < length; i++)
	{
		if (str1[i] == '\n')
		{
			str1[i] = '\0';
			break;
		}
		if (str1[i] == '\0')
		{
			str1[i] = str1[i - 1];
			break;
		}
	}

	


	char str2[MAX];
	printf("请输入第二段字符串：");
	fgets(str2, MAX, stdin);
	for (int i = 0; i < MAX; i++)
	{
		if (str2[i] == '\n')
		{
			str2[i] = '\0';
		}
	}

	printf("请输入要连接的字符串个数：");
	int n;
	scanf("%d", &n);
	strncat(str1, str2, n);
	
	/*
		strncat函数

		函数概要：
		strncat 函数用于拷贝源字符串中的 n 个字符到目标数组的字符串后边，并在末尾添加结束符 '\0'。
		如果源字符串的长度小于 n，那么不会像 strncpy 函数那样使用 '\0' 进行填充（但结束符 '\0' 还是有的）。
		另外，目标数组中的原有的字符串并不算在 n 中。
		
		函数原型：
			#include <string.h>
			...
			char *strncat(char *dest, const char *src, size_t n);

		参数解析：
		参数						含义
		dest					指向用于存放字符串的目标数组，它应该包含一个字符串，并且提供足够容纳连接后的总字符串长度的空间（包含结束符 '\0'）
		src						指向待连接的源字符串，该参数不应该与 dest 参数指向的位置发生重叠
		n						指定待连接的源字符串的最大长度
	*/

	printf("输出结果：%s", str1);
	
}

//主函数
//
int main()
{
	/* 
		索引					作用
		test1				利用指针模拟实现strcat拷贝
		test2				利用scanf搭配strcat函数实现拷贝（重点部分，断定为什么不推荐使用scanf进行字符串数组的拷贝）
		test3				实现用fgets搭配strcat函数使用实现拷贝
		test4				利用指针模拟strcat函数实现拷贝（含中英文）
		test5				利用strcat函数对选定字符进行拷贝
	*/


	test5();
	return 0;
}

